﻿using System.Collections;
using System.Collections.Generic;
using NJabber.Client.StanzaFactories;
using System;
using System.ComponentModel.Design;

namespace NJabber.Client
{
    public class StandartClientRuntimeFactory : IClientRuntimeFactory
    {
        private static StandartClientRuntimeFactory defaultFactory;

        public static IClientRuntimeFactory Default
        {
            get { return (defaultFactory ?? (defaultFactory = new StandartClientRuntimeFactory())); }
        }

        public XmppClientRuntime CreateRuntime()
        {
            IServiceProvider serviceProvider = CreateServiceProvider();
            return new StandartClientRuntime(serviceProvider);            
        }

        protected virtual IServiceProvider CreateServiceProvider()
        {
            ServiceContainer container = new ServiceContainer();

            IXmppConnection connection = new XmppConnection();
            IRosterStanzaFactory rosterStanzaFactory = new RosterStanzaFactory();
            ISubscriptionStanzaFactory subscriptionStanzaFactory = new SubscriptionStanzaFactory();
            IRosterCache rosterCache = CreateRosterCache(connection, rosterStanzaFactory);
            IPresenceSubscriptionRegistry registry = CreateSubscriptionRegistry(connection, subscriptionStanzaFactory);
            PresenceStatusStorage statusStorage = new PresenceStatusStorage();
            IEnumerable<IStanzaHandler> handlers = CreateStanzaHandlers(rosterCache, statusStorage, registry);

            container.AddService(typeof(IXmppConnection), connection);
            container.AddService(typeof(IRosterCache), rosterCache);
            container.AddService(typeof(IEnumerable<IStanzaHandler>), handlers);

            container.AddService(typeof(IMessageStanzaFactory), new MessageStanzaFactory());
            container.AddService(typeof(IPresenceStanzaFactory), new PresenceStanzaFactory());
            container.AddService(typeof(IRosterStanzaFactory), rosterStanzaFactory);
            container.AddService(typeof(ISubscriptionStanzaFactory), subscriptionStanzaFactory);

            container.AddService(typeof(IPresenceSubscriptionRegistry), registry);
            container.AddService(typeof(IPresenceStatusProvider), statusStorage);
            container.AddService(typeof(IPresenceStatusUpdater), statusStorage);

            return container;
        }

        protected IRosterCache CreateRosterCache(IXmppConnection connection, IRosterStanzaFactory factory)
        {
            IRosterUpdater updater = new RosterUpdater(connection, factory);
            IRosterSynchronizer synchronizer = new RosterSynchronizer(connection, factory, updater);
            RosterCache rosterCache = new RosterCache(synchronizer);
            return rosterCache;
        }       

        private IPresenceSubscriptionRegistry CreateSubscriptionRegistry(IXmppConnection connection, ISubscriptionStanzaFactory factory)
        {
            IPresenceSubscriptionResponder responder = new PresenceSubscriptionResponder(connection, factory);
            return new PresenceSubscriptionRegistry(responder);
        }

        private IEnumerable<IStanzaHandler> CreateStanzaHandlers(IRosterCache rosterCache, IPresenceStatusUpdater updater, IPresenceSubscriptionRegistry registry)
        {
            GenericStanzaHandler mainHandler = new GenericStanzaHandler();
            mainHandler.IqHandlers.Add(new IqStanzaHandler(rosterCache));
            mainHandler.PresenceHandlers.Add(new PresenceStanzaHandler(updater, registry));
            mainHandler.MessageHandlers.Add(new MessageStanzaHandler());
            return new[] {mainHandler};
        }
    }

    public interface IClientRuntimeFactory
    {
        XmppClientRuntime CreateRuntime();
    }
}
